# 函数递归
# 写一个函数，来求n的阶乘（n是正整数）
# 3! = 3 * 2! 即factorial(3) = 3 * factorial(2)
# = 3 * 2 * factorial(1) = 3 * 2 * 1

# 函数栈帧的进一步讨论：
# 对于递归调用来说，每次调用都是在使用同一个函数
# 但区分不同的栈帧，不是通过函数是否相同
# 而是通过调用关系，只要一个函数a中调用了一个函数x,
# 无论函数a 和 函数x 是否相同，其对应的函数栈帧都是不同的
# 不同的函数栈帧开辟了不同的内存空间

# 而且每个栈帧中的变量都是不同的

# 递归：要写出一个递归代码，必须分析
# 1、对于函数参数的分类，参数取不同的值，判断是否可以结束
# 2、对于递归公式的表达

# 递归代码和循环代码进行比较：
# 递归的缺点：
# 1、递归的代码容易出现栈溢出的情况
#    调用函数就需要函数栈帧，当递归的超过了最大递归深度(maximum recursion depth)
#    就会出现栈溢出错误
# 比如：求阶乘时，用递归代码求不出999的阶乘，但是用循环代码能求出9999的阶乘
# 2、递归的代码的运行速度较慢
#    因为递归都是在反复调用函数，每次调用函数，每一层函数返回值，都需要花费时间
# 递归的优点：
# 1、代码非常简洁，尤其是处理一些
#    问题本身就是通过递归的方式定义的情况时
# 

# Method1: 递归求n的阶乘
"""
while True:
    n = int(input('请输入一个正整数n：'))
    if n > 0:
        def factorial1(x):
            if x > 1:
                return x * factorial1(x - 1)
            return x

        # factorial1也可以写成另外一种递归形式：
        # 此时将输入分为两类：1、等于1，不需要递归  2、不等于1，需要递归
        # def factorial1(x):
        #     if x == 1:
        #         return x
        #     return x * factorial1(x - 1)

        r = factorial1(n)
        print(f'n的阶乘是：{r}')
        print('\n输入0退出程序\n')

    elif n < 0:
        print('输错了，请输入一个正整数')
        continue

    else:
        exit(0)
"""


# Method2: 用循环
# 写一个函数，来求n的阶乘（n是正整数）
# 3！= 3 * 2 * 1

while True:
    n = int(input('请输入一个正整数n：'))
    if n > 0:
        # 注意：下面这句return不能缩进错误，
        # 因为如果写成
        """
        for i in range(1, x + 1):
            theMul *= i
            return theMul
        """
        # 由于python中for循环的特点，在第一次执行循环体时i = 1进入循环体执行
        # 然而循环体中有 return theMul 这句话，会在第一次直接return
        # 无论n是什么输入，factorial2这个函数都将返回1

        def factorial2(x):
            theMul = 1
            for i in range(1, x + 1):
                theMul *= i
            return theMul


        r = factorial2(n)
        print(f'n的阶乘是：{r}')
        print('\n输入0退出程序\n')

    elif n < 0:
        print('输错了，请输入一个正整数')
        continue

    else:
        exit(0)
